package com.wzkun.aicraft.ai;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.wzkun.aicraft.ai.tools.*;
import com.wzkun.aicraft.exception.BusinessException;
import com.wzkun.aicraft.exception.ErrorCode;
import com.wzkun.aicraft.model.enums.CodeGenTypeEnum;
import com.wzkun.aicraft.service.ChatHistoryService;
import dev.langchain4j.community.store.memory.chat.redis.RedisChatMemoryStore;
import dev.langchain4j.data.message.ToolExecutionResultMessage;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.service.AiServices;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

/**
 * AI服务创建工厂
 *
 * @author wzk
 * @since 2025/11/10
 */
@Configuration
@Slf4j
public class AiCodeGeneratorServiceFactory {

    @Resource
    private ChatModel chatModel;

    @Resource
    private StreamingChatModel openAiStreamingChatModel;

    @Resource
    private StreamingChatModel reasoningStreamingChatModel;

    @Resource
    private RedisChatMemoryStore redisChatMemoryStore;

    @Resource
    private ChatHistoryService chatHistoryService;

    @Resource
    private ToolManager toolManager;

    /**
     * AI 服务实例缓存
     * 缓存策略：
     * - 最大缓存 1000 个实例
     * - 写入后 30 分钟过期
     * - 访问后 10 分钟过期
     */
    private final Cache<String, AiCodeGeneratorService> serviceCache = Caffeine.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(Duration.ofMinutes(30))
            .expireAfterAccess(Duration.ofMinutes(10))
            .removalListener((key, value, cause) -> {
                log.debug("AI 服务实例被移除，缓存键: {}, 原因: {}", key, cause);
            })
            .build();

    /**
     * 构建缓存键
     */
    private String buildCacheKey(long appId, CodeGenTypeEnum codeGenType) {
        return appId + "_" + codeGenType.getValue();
    }

    /**
     * 根据 appId 和代码生成类型获取服务（带缓存）
     */
    public AiCodeGeneratorService getAiCodeGeneratorService(long appId, CodeGenTypeEnum codeGenType) {
        String cacheKey = buildCacheKey(appId, codeGenType);
        return serviceCache.get(cacheKey, key -> createAiCodeGeneratorService(appId, codeGenType));
    }

    /**
     * 根据 appId 获取服务（带缓存） 这个方法是为了兼容历史逻辑
     * 该方法提供了一个带缓存的获取 AiCodeGeneratorService 实例的方式
     * 如果缓存中不存在对应 appId 的服务实例，则会通过 createAiCodeGeneratorService 方法创建新的服务实例
     *
     * @param appId 应用ID，用于标识和获取对应的服务实例
     * @return 返回对应 appId 的 AiCodeGeneratorService 实例，如果不存在则创建新的实例
     */
    public AiCodeGeneratorService getAiCodeGeneratorService(long appId) {
        // 使用 serviceCache 的 get 方法，传入 appId 和函数式接口 this::createAiCodeGeneratorService
        // 如果缓存中不存在对应 appId 的服务，则会调用 createAiCodeGeneratorService 方法创建新实例
//        return serviceCache.get(appId, this::createAiCodeGeneratorService);
        return getAiCodeGeneratorService(appId, CodeGenTypeEnum.HTML);
    }

    /**
     * 创建新的 AI 服务实例
     * 根据应用ID和代码生成类型构建相应的AI服务

     *
     * @param appId 应用id，用于构建独立的对话记忆
     * @param codeGenType 生成类型，决定使用哪种AI模型配置
     * @return 返回配置好的AiCodeGeneratorService实例
     */
    private AiCodeGeneratorService createAiCodeGeneratorService(long appId, CodeGenTypeEnum codeGenType) {
        // 根据 appId 构建独立的对话记忆窗口
        // 设置最大保存20条对话记录
        MessageWindowChatMemory chatMemory = MessageWindowChatMemory
                .builder()
                .id(appId)
                .chatMemoryStore(redisChatMemoryStore)  // 使用Redis作为存储后端
                .maxMessages(100)
                .build();
        // 从数据库加载历史对话到记忆中
        // 最多加载20条历史记录
        chatHistoryService.loadChatHistoryToMemory(appId, chatMemory, 20);
        // 根据代码生成类型选择不同的模型配置
        return switch (codeGenType) {
            // Vue 项目生成使用推理模型
            case VUE_PROJECT -> AiServices.builder(AiCodeGeneratorService.class)
                    .streamingChatModel(reasoningStreamingChatModel)  // 使用推理流式模型
                    .chatMemoryProvider(memoryId -> chatMemory)  // 设置对话记忆
                    .tools(toolManager.getAllTools())
//                    .tools(
//                            new FileWriteTool(), // 添加文件写入工具
//                            new FileReadTool(), // 添加文件读取工具
//                            new FileModifyTool(), // 文件修改工具
//                            new FileDirReadTool(), // 文件目录读取工具
//                            new FileDeleteTool() // 文件删除工具
//                            toolManager.getAllTools()
//                    )
                    .hallucinatedToolNameStrategy(toolExecutionRequest -> ToolExecutionResultMessage.from(
                            toolExecutionRequest, "Error: there is no tool called " + toolExecutionRequest.name()
                    ))  // 处理不存在的工具调用 工具调用幻觉问题
                    .build();
            // HTML 和多文件生成使用默认模型
            case HTML, MULTI_FILE -> AiServices.builder(AiCodeGeneratorService.class)
                    .chatModel(chatModel)  // 设置默认聊天模型
                    .streamingChatModel(openAiStreamingChatModel)  // 设置OpenAI流式模型
                    .chatMemory(chatMemory)  // 设置对话记忆
                    .build();
            // 不支持的代码生成类型
            default -> throw new BusinessException(ErrorCode.SYSTEM_ERROR,
                    "不支持的代码生成类型: " + codeGenType.getValue());
        };
    }

//    /**
//     * 根据appId 创建单独的AI Service (不带缓存)
//     * 该方法为每个应用实例创建独立的AI代码生成服务，包含独立的对话记忆
//     *
//     * @param appId 应用id，用于区分不同应用的对话记忆
//     * @return AI Service 返回配置好的AI代码生成服务实例
//     */
//    public AiCodeGeneratorService getAiCodeGeneratorService(long appId) {
//        // 创建基于Redis的对话记忆存储
//        // 使用MessageWindowChatMemory实现，限制最多保存20条消息
//        MessageWindowChatMemory chatMemory = MessageWindowChatMemory
//                .builder()
//                .id(appId) // 使用appId作为记忆ID，确保每个应用有独立的对话记忆
//                .chatMemoryStore(redisChatMemoryStore) // 设置Redis作为记忆存储后端
//                .maxMessages(20) // 设置最大消息保存数量
//                .build();
//        // 使用AiServices构建器创建AI服务实例
//        return AiServices.builder(AiCodeGeneratorService.class)
//                .chatModel(chatModel) // 设置常规聊天模型
//                .streamingChatModel(streamingChatModel) // 如果需要流式响应，请使用streamingChatModel
//                // 根据memoryId 创建独立的对话记忆
//                .chatMemory(chatMemory)
//                .build();
//    }

    /**
     * 创建AI代码生成服务
     *
     * @return AI代码生成服务
     */
    @Bean
    public AiCodeGeneratorService createAiCodeGeneratorService(RedisChatMemoryStore redisChatMemoryStore) {
//        return AiServices.create(AiCodeGeneratorService.class,chatModel);
        return AiServices.builder(AiCodeGeneratorService.class)
                .chatModel(chatModel)
                .streamingChatModel(openAiStreamingChatModel) // 如果需要流式响应，请使用streamingChatModel
                // 根据memoryId 创建独立的对话记忆
                .chatMemoryProvider(memoryId -> MessageWindowChatMemory
                        .builder()
                        .id(memoryId)
                        .chatMemoryStore(redisChatMemoryStore)
                        .maxMessages(20)
                        .build())
                .build();
    }
}
